package com.vcc.service.impl;


import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson2.JSONObject;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.vcc.core.exception.NotFoundException;
import com.vcc.core.exception.ProgramException;
import com.vcc.core.util.DateUtil;
import com.vcc.core.util.EncryptUtil;
import com.vcc.core.util.IdWorker;
import com.vcc.core.util.RegexUtil;
import com.vcc.data.entity.Role;
import com.vcc.data.entity.User;
import com.vcc.data.mapper.UserMapper;
import com.vcc.service.boss.request.user.UserRegisterDto;
import com.vcc.service.client.dto.user.ExternalUserRegisterDto;
import com.vcc.service.sa.BossUserUtil;
import com.vcc.service.service.BossUserService;
import com.vcc.service.service.UserService;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.vcc.data.entity.table.BossUserTableDef.BOSS_USER;
import static com.vcc.data.entity.table.UserTableDef.USER;
import static com.vcc.data.entity.table.WalletTableDef.WALLET;
//import static com.vcc.data.entity.table.USER;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {


    @Resource
    private BossUserService bossUserService;


    @Override
    public User getById(Long id) {
        QueryChain<User> queryChain = queryChain();
        queryChain.select(USER.ALL_COLUMNS);
        // 统计 registeCounT 根据 register_id
        queryChain.select("(SELECT COUNT(*) FROM vcc_user AS u WHERE u.register_id = " + id + ") AS registerCount");
        queryChain.where(USER.ID.eq(id));
        return queryChain.oneOpt().orElseThrow(() -> new NotFoundException("没有当前用户"));
//
//        return mapper.findById(id).orElseThrow(() -> new NotFoundException("没有当前用户"));
    }

    @Override
    public String getAccountById(Long userId) {
        return mapper.findAccountById(userId);
    }

    @Override
    public Boolean existsByAccount(String account) {
        return queryChain().eq(User::getAccount, account).exists();
    }

    @Override
    public List<Long> listByDealerId(Long dealerId) {
        return mapper.findIdByBeLongToDealer(dealerId);
    }


    @Override
    public List<String> listAccountByIds(Collection<Long> ids) {
        return queryChain()
                .in(User::getId, ids)
                .select(User::getAccount)
                .list()
                .stream()
                .map(User::getAccount)
                .collect(Collectors.toList());
    }

    @Override
    public User login(String account) {
        QueryChain<User> userQueryChain = queryChain();
        userQueryChain.select(USER.ALL_COLUMNS);
        userQueryChain.select("parent.account as parentAccount");
        userQueryChain.leftJoin(USER.as("parent")).on(USER.PARENT_ID.eq(USER.ID));
        userQueryChain.where(USER.ACCOUNT.eq(account.trim()));
        return userQueryChain.oneOpt().orElseThrow(() -> new NotFoundException("没有当前账号，无法登录"));
    }

    @Override
    public User login(String account, String password) {
        QueryChain<User> userQueryChain = queryChain();
        userQueryChain.select(USER.ALL_COLUMNS);
        userQueryChain.select("dealer.account as parentAccount");
        userQueryChain.leftJoin(USER.as("dealer")).on(USER.PARENT_ID.eq(USER.ID));
        userQueryChain.where(USER.ACCOUNT.eq(account)
                .and(USER.PASSWORD.eq(password)));
        return userQueryChain.oneOpt().orElseThrow(() -> new NotFoundException("账号或密码错误"));
    }


    @Transactional
    @Override
    public User init(UserRegisterDto userRegisterDto, Long dealerId) {
        if (queryChain().eq(User::getEmail, userRegisterDto.getEmail()).exists()) {
            throw new ProgramException("当前邮箱已存在无法创建");
        }
        if (queryChain().eq(User::getAccount, userRegisterDto.getEmail()).exists()) {
            throw new ProgramException("当前账号已存在无法创建");
        }
        User user = new User();
        Long id;
        do {
            id = IdWorker.getLongId();
        } while (queryChain().eq(User::getId, id).exists());
        user.setId(id);
        user.setAccount(userRegisterDto.getEmail());
        user.setEmail(userRegisterDto.getEmail());
        user.setUsername(userRegisterDto.getUsername());
        user.setRemark(userRegisterDto.getRemark());
        user.setStatus(0);
        //上级id在客户端存在时则为子账号
        if (existsById(dealerId)) {
            user.setParentId(dealerId);
            user.setBeLongToDealer(mapper.getBeLongToDealerById(dealerId));
            user.setRegisterSource("client");
            user.setRegisterId(dealerId);
        } else {
            user.setBeLongToDealer(dealerId);
            user.setParentId(0L);
            user.setRegisterSource("system");
            user.setRegisterId(dealerId);
        }
        String invitationCode;
        do {
            invitationCode = RandomUtil.randomString(8);
        } while (existsByInvitationCode(invitationCode));
        user.setInvitationCode(invitationCode);
        user.setHasBindGoogle(false);
        user.setSalt(IdUtil.randomUUID());
        user.setPassword(EncryptUtil.encryptValue(userRegisterDto.getPassword(), user.getSalt()));
        user.setPayPassword(EncryptUtil.encryptValue(userRegisterDto.getPayPassword(), user.getSalt()));
        save(user);
        return user;
    }

    @Override
    public User init(ExternalUserRegisterDto userRegisterDto) {
        if (queryChain().eq(User::getEmail, userRegisterDto.getEmail()).exists()) {
            throw new ProgramException("当前邮箱已存在无法创建");
        }
        if (queryChain().eq(User::getAccount, (userRegisterDto.getEmail())).exists()) {
            throw new ProgramException("当前账号已存在无法创建");
        }
        Long id;
        do {
            id = IdWorker.getLongId();
        } while (queryChain().eq(User::getId, id).exists());
        User user = new User();
        user.setId(id);
        user.setAccount(userRegisterDto.getEmail());
        user.setEmail(userRegisterDto.getEmail());
        user.setUsername(userRegisterDto.getUsername());
        user.setRemark("");
        user.setStatus(0);
        user.setParentId(0L);
        if (userRegisterDto.getInvitationCode().length() == 6) {
            user.setBeLongToDealer(bossUserService.getByInvitationCode(userRegisterDto.getInvitationCode()));
        } else {
            user.setBeLongToDealer(getDealerIdById(userRegisterDto.getRegisterId()));
        }
        user.setHasBindGoogle(false);
        user.setSalt(IdUtil.randomUUID());
        user.setPassword(EncryptUtil.encryptValue(userRegisterDto.getPassword(), user.getSalt()));
        user.setRegisterId(userRegisterDto.getRegisterId());
        user.setRegisterSource(userRegisterDto.getRegisterSource());
        user.setPayPassword(null);
        String invitationCode;
        do {
            invitationCode = RandomUtil.randomString(8);
        } while (existsByInvitationCode(invitationCode));
        user.setInvitationCode(invitationCode);
        save(user);
        return user;
    }

    @Override
    public boolean updateStatusById(Long id, Integer status) {
        return updateChain().eq(User::getId, id).set(User::getStatus, status).update();
    }

    @Override
    public boolean bossUpdateStatusById(Long id, Integer status) {
        if (BossUserUtil.hasAllData()) {
            return updateChain()
                    .eq(User::getId, id)
                    .where(USER.STATUS.ne(4))
                    .where(USER.STATUS.ne(3))
                    .set(User::getStatus, status).update();
        } else {
            throw new ProgramException("权限不够");
        }
    }

    @Override
    public boolean updateStatusByParentId(Long parentId, Integer status) {
        if (RegexUtil.checkObjectIsNotNull(parentId)) {
            return updateChain()
                    .eq(User::getParentId, parentId)
                    .where(USER.STATUS.ne(4))
                    .where(USER.STATUS.ne(3))
                    .set(User::getStatus, status).update();
        } else {
            throw new ProgramException("父级ID不能为空");
        }
    }

    @Override
    public boolean updatePasswordById(Long id, String password) {
        return updateChain().eq(User::getId, id).set(User::getPassword, (password)).update();

    }

    @Override
    public boolean updatePayPasswordById(Long id, String payPassword) {
        return updateChain().eq(User::getId, id).set(User::getPayPassword, (payPassword)).update();
    }

    @Override
    public boolean updateRemarkById(Long id, String remark) {
        return updateChain().eq(User::getId, id).set(User::getRemark, remark).update();
    }

    @Override
    public boolean updateAdminRemarkById(Long id, String remark) {
        return updateChain().eq(User::getId, id).set(User::getAdminRemark, remark).update();
    }

    @Override
    public List<Long> listIds() {
        return mapper.findAllId();
    }

    @Override
    public List<User> listDealer() {

        return mapper.findAllDealer().stream().peek(it -> it.setAccount(it.getAccount())).collect(Collectors.toList());
    }

    @Override
    public List<User> listByEmail(String email, Long userId, Role role) {
        if (role.getHasAllData()) {
            return queryChain().like(User::getEmail, email).limit(20).where(USER.PARENT_ID.eq(userId).or(USER.ID.eq(userId))).list();
        } else {
            throw new ProgramException("权限不够");
        }
    }

    @Override
    public List<User> listByEmail(String email) {
        if (BossUserUtil.hasAllData()) {
            return queryChain().like(User::getEmail, email).limit(20).list();
        } else {
            return queryChain().like(User::getEmail, email).eq(User::getBeLongToDealer, BossUserUtil.getId()).limit(20).list();

        }
    }

    @Override
    public User getByEmail(String email) {
        return queryChain().eq(User::getEmail, email).oneOpt().orElseThrow(() -> new NotFoundException("当前邮箱不存在"));
    }

    @Override
    public Page<User> paging(Page<User> pageable, Long userId, Role role, Long targetUserId, Integer status, String remark) {
        QueryChain<User> queryChain = queryChain();
        if (role.getHasAllData()) {
            queryChain
                    .leftJoin(USER.as("dealer"))
                    .on(USER.PARENT_ID.eq(USER.ID))
                    .where(USER.PARENT_ID.eq(userId).or(USER.ID.eq(userId)));
            if (RegexUtil.checkObjectIsNotNull(targetUserId)) {
                queryChain.eq(User::getId, targetUserId);
            }
        } else {
            queryChain.eq(User::getId, userId);
        }

        if (RegexUtil.checkObjectIsNotNull(status)) {
            queryChain.eq(User::getStatus, status);
        }
        if (RegexUtil.checkObjectIsNotNull(remark)) {
            queryChain.like(User::getRemark, remark);
        }
        queryChain.orderBy(User::getCreateDate, false);
        return queryChain.page(pageable);
    }

    @Override
    public Page<User> paging(Page<User> pageable, Long targetUserId, Integer status, String remark, String account, String email, Long dealerId, String sorter, Long parentId) {
        QueryChain<User> queryChain = queryChain();
        queryChain.select(USER.ALL_COLUMNS);
        queryChain.select(USER.as("parent").EMAIL.as("parentAccount"));
        //统计 registerCount 根据 register_id
        queryChain.select("(SELECT COUNT(*) FROM vcc_user AS u WHERE u.register_id = vcc_user.id) AS registerCount");
        queryChain.select(BOSS_USER.as("dealer").EMAIL.as("dealerAccount"));
        queryChain.leftJoin(BOSS_USER.as("dealer")).on(USER.BE_LONG_TO_DEALER.eq(BOSS_USER.ID));
        queryChain.leftJoin(USER.as("parent")).on(USER.PARENT_ID.eq(USER.as("parent").ID));
        Long bossUserId = BossUserUtil.getIdNotNull();
        if (!BossUserUtil.hasAllData()) {
            queryChain.and(
                    BOSS_USER.as("dealer").ID.eq(bossUserId)
                            .or(BOSS_USER.as("dealer").PARENT_ID.eq(bossUserId))
            );
        }
        if (RegexUtil.checkObjectIsNotNull(targetUserId)) {
            queryChain.eq(User::getId, targetUserId);
        }
        if (RegexUtil.checkObjectIsNotNull(status)) {
            queryChain.eq(User::getStatus, status);
        }
        if (RegexUtil.checkObjectIsNotNull(dealerId)) {
            queryChain.eq(User::getBeLongToDealer, dealerId);
        }
        if (RegexUtil.checkObjectIsNotNull(remark)) {
            queryChain.like(User::getRemark, remark);
        }
        if (RegexUtil.checkObjectIsNotNull(email)) {
            queryChain.like(User::getEmail, email);
        }
        if (RegexUtil.checkObjectIsNotNull(parentId)) {
            queryChain.where(USER.PARENT_ID.eq(parentId).or(USER.ID.eq(parentId)));
        }
        if (RegexUtil.checkObjectIsNotNull(account)) {
            queryChain.like(User::getAccount, account);
        }
        if (StringUtils.isNotBlank(sorter)) {
            String[] sorts = sorter.split("_");
            if (sorts.length == 2) {
                if (sorts[0].equals("usdBalance")) {
                    queryChain.leftJoin(WALLET).on(WALLET.USER_ID.eq(USER.ID));
                    queryChain.where(WALLET.CURRENCY_CODE.eq("USD"));
                    boolean isAsc = sorts[1].equals("asc");
                    queryChain.orderBy(WALLET.USABLE_QUOTA, isAsc);
                }
            } else {
                queryChain.orderBy(User::getCreateDate, false);
            }
        } else {
            queryChain.orderBy(User::getCreateDate, false);

        }

        return queryChain.page(pageable);
    }


    @Override
    public Long getParentIdById(Long id) {
        Long parentId = mapper.findParentIdById(id);
        return parentId != null ? parentId : 0L;
    }

    @Override
    public Long getDealerIdById(Long id) {
        return Optional.of(mapper.getBeLongToDealerById(id)).orElseThrow(() -> new NotFoundException("没有当前用户的代理信息"));
    }

    @Override
    public Boolean active(Long id) {
        return updateChain().eq(User::getId, id).set(User::getStatus, 0).update();
    }

    @Override
    public Boolean existsById(Long id) {
        return queryChain().eq(User::getId, id).exists();
    }

    @Override
    public Boolean bindGoogle(Long id, String googleSecret) {
        return updateChain()
                .eq(User::getId, id)
                .set(User::getGoogleSecret, googleSecret)
                .set(User::getHasBindGoogle, true)
                .set(User::getBindGoogleDate, new Date())
                .update();
    }

    @Override
    public Boolean clearGoogle(Long id) {
        return updateChain()
                .eq(User::getId, id)
                .set(User::getGoogleSecret, "")
                .set(User::getHasBindGoogle, false)
                .set(User::getBindGoogleDate, null)
                .update();
    }

    @Override
    public Integer getStatusById(Long id) {
        QueryChain<User> userQueryChain = queryChain();
        userQueryChain.select(USER.STATUS);
        userQueryChain.where(USER.ID.eq(id));
        return getObjAs(userQueryChain, Integer.class);
    }

    @Override
    public Long countByParentId(Long parentId) {
        QueryChain<User> queryChain = queryChain();
        queryChain.where(USER.PARENT_ID.eq(parentId));
        return count(queryChain);
    }

    @Override
    public List<JSONObject> statistics() {
        //统计 register_id 的次数 作为 registerCount where register_source = client

        QueryChain<User> userQueryChain = queryChain();
        userQueryChain.select("COUNT(register_id) AS registerCount", "register_id AS userId");
        userQueryChain.where(USER.REGISTER_SOURCE.eq("client"));
        userQueryChain.where(USER.CREATE_DATE.between(
                DateUtil.getDayBeginDate(DateTime.now().offset(DateField.DAY_OF_MONTH, -1)),
                DateUtil.getDayEndDate(DateTime.now().offset(DateField.DAY_OF_MONTH, -1))));
        userQueryChain.groupBy(USER.REGISTER_ID);
        return mapper.selectListByQueryAs(userQueryChain, Row.class).stream().map(JSONObject::new).toList();
    }

    @Override
    public List<JSONObject> statistics(DateTime startDate, DateTime endDate) {
        if (startDate == null || endDate == null) {
            return List.of();
        }
        //统计 register_id 的次数 作为 registerCount where register_source = client
        QueryChain<User> userQueryChain = queryChain();
        userQueryChain.select("COUNT(register_id) AS registerCount", "register_id AS userId");
        userQueryChain.where(USER.REGISTER_SOURCE.eq("client"));
        userQueryChain.where(USER.CREATE_DATE.between(
                DateUtil.getDayBeginDate(startDate),
                DateUtil.getDayEndDate(endDate)));
        userQueryChain.groupBy(USER.REGISTER_ID);
        return mapper.selectListByQueryAs(userQueryChain, Row.class).stream().map(JSONObject::new).toList();
    }

    @Override
    public Integer statistics(List<String> dates) {
        if (dates == null || dates.isEmpty()) {
            return 0;
        }
        QueryChain<User> userQueryChain = queryChain();
        userQueryChain.select("COUNT(register_id) AS registerCount");
        userQueryChain.where(USER.REGISTER_SOURCE.eq("client"));
        userQueryChain.where(USER.CREATE_DATE.between(
                DateUtil.getDayBeginDate(DateUtil.parse(dates.get(0))),
                DateUtil.getDayEndDate(DateUtil.parse(dates.get(dates.size() - 1)))));
        return getObjAs(userQueryChain, Integer.class);
    }

    @Override
    public Boolean setInvitationCode(Long id, String invitationCode) {
        return updateChain()
                .eq(User::getId, id)
                .set(User::getInvitationCode, invitationCode)
                .update();
    }

    @Override
    public Boolean existsByInvitationCode(String invitationCode) {
        return queryChain().eq(User::getInvitationCode, invitationCode).exists();
    }

    @Override
    public Long getIdByInvitationCode(String invitationCode) {
        QueryChain<User> queryChain = queryChain();
        queryChain.select(USER.ID);
        queryChain.where(USER.INVITATION_CODE.eq(invitationCode));
        return queryChain.oneAsOpt(Long.class).orElseThrow(() -> new ProgramException("没有这个邀请码"));
    }

    @Override
    public Boolean updateStatusAndAdminRemarkById(Long id, Integer status, String remark) {
        return updateChain()
                .eq(User::getId, id)
                .set(User::getStatus, status)
                .set(User::getAdminRemark, remark)
                .set(User::getRemark, remark)
                .update();
    }


    @Override
    public Long countByRegisterId(Long registerId) {
        return queryChain().eq(User::getRegisterId, registerId).count();
    }

    @Override
    public Map<String, Long> userSummary() {
        QueryChain<User> query = queryChain().from(User.class);
        query.select("COUNT(vcc_user.id) AS totalCount");
        query.select("COUNT(CASE WHEN vcc_user.status = 0 THEN 1 ELSE NULL END) AS activeCount");
        query.select("COUNT(CASE WHEN vcc_user.status = 1 THEN 1 ELSE NULL END) AS freezeCount");
        query.select("COUNT(CASE WHEN vcc_user.status = 2 THEN 1 ELSE NULL END) AS riskCount");
        query.select("COUNT(CASE WHEN vcc_user.status = 3 THEN 1 ELSE NULL END) AS closeCount");
        Row row = mapper.selectOneByQueryAs(query, Row.class);
        if (row == null) {
            return Map.of();
        }
        if (!BossUserUtil.hasAllData()) {
            query.leftJoin(BOSS_USER.as("dealer")).on(USER.BE_LONG_TO_DEALER.eq(BOSS_USER.as("dealer").ID));
            Long bossUserId = BossUserUtil.getIdNotNull();
            query.and(
                    BOSS_USER.as("dealer").ID.eq(bossUserId)
                            .or(BOSS_USER.as("dealer").PARENT_ID.eq(bossUserId))
            );
        }
        return (Map<String, Long>) query.oneAs(Map.class);
    }
}
